#include <dirent.h>
#include <sys/stat.h>
#include "esp_log.h"
#include "esp_lvgl_port.h"
#include "esp_heap_caps.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "screenshot.h"
#include "sd_card.h"
#include "func_ui.h"

//#include "lv_snapshot.h"
#define TJE_IMPLEMENTATION // 定义TJE实现宏，用于JPEG编码
#include "tiny_jpeg.h"     // 包含JPEG编码库tiny_jpeg

#define SCREENSHOT_SD_PATH    SD_MOUNT_POINT"/image"
#define SCREENSHOT_SD_PATH_MAX  (64)

static const char *TAG = "screenshot";
// 静态函数声明：数据预处理函数
static void md_data_pre_processing(lv_img_dsc_t *snapshot, uint16_t bpp, screenshot_sv_t screenshot_sv);

lv_res_t lv_snapshot_take_to_buf(lv_obj_t *obj, lv_img_cf_t cf, lv_img_dsc_t *dsc, void *buf, uint32_t buff_size);
uint32_t lv_snapshot_buf_size_needed(lv_obj_t *obj, lv_img_cf_t cf);
/** Take snapshot for object with its children, alloc the memory needed.
 *
 * @param obj    The object to generate snapshot.
 * @param cf     color format for generated image.
 *
 * @return a pointer to an image descriptor, or NULL if failed.
 */
lv_img_dsc_t *md_lv_snapshot_take(lv_obj_t *obj, lv_img_cf_t cf)
{
    LV_ASSERT_NULL(obj);
    uint32_t buff_size = lv_snapshot_buf_size_needed(obj, cf);
    // // 检查可用内存
    // size_t free_psram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
    // size_t free_internal = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);

    // ESP_LOGI("SCREENSHOT", "Free PSRAM: %d, Free Internal: %d", free_psram, free_internal);
    // ESP_LOGI("SCREENSHOT", "Buff size: %d", buff_size);
    //void *buf = lv_mem_alloc(buff_size);
    void *buf = heap_caps_malloc(buff_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
    // void *buf = malloc(buff_size);
    if (buf == NULL) {
        return NULL;
    }

    // lv_img_dsc_t *dsc = lv_mem_alloc(sizeof(lv_img_dsc_t));
    lv_img_dsc_t *dsc = (lv_img_dsc_t *)heap_caps_malloc(sizeof(lv_img_dsc_t), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
    // lv_img_dsc_t *dsc = (lv_img_dsc_t *)malloc(sizeof(lv_img_dsc_t));

    if (dsc == NULL) {
        // free(buf);
        heap_caps_free(buf);
        // lv_mem_free(buf);
        return NULL;
    }
    lvgl_port_lock(0); // 进入LVGL临界区（确保线程安全）
    if (lv_snapshot_take_to_buf(obj, cf, dsc, buf, buff_size) == LV_RES_INV) {
        // free(buf);
        // free(dsc);
        heap_caps_free(buf);
        heap_caps_free(dsc);

        // lv_mem_free(buf);
        // lv_mem_free(dsc);
        return NULL;
    }
    lvgl_port_unlock(); // 退出LVGL临界区
    ESP_LOGI(TAG, "snapshot_take ok");
    return dsc;
}
/** Free the snapshot image returned by @ref lv_snapshot_take
 *
 * It will firstly free the data image takes, then the image descriptor.
 *
 * @param dsc    The image descriptor generated by lv_snapshot_take.
 *
 */
void md_lv_snapshot_free(lv_img_dsc_t *dsc)
{
    if (!dsc)
        return;

    if (dsc->data)
    {
        //free((void *)dsc->data);
        heap_caps_free((void *)dsc->data);
    }

   //free(dsc);
    heap_caps_free(dsc);
}
/**
 * @brief 创建截图并保存为指定格式
 * @param obj 要截图的LVGL对象
 * @param cf 颜色格式
 * @param screenshot_sv 截图保存格式（PNG、BMP、JPEG）
 * @param filename 保存的文件名
 * @return true 成功创建并保存截图；false 失败
 */
bool screenshot_create(lv_obj_t *obj, lv_img_cf_t cf, screenshot_sv_t screenshot_sv, const char *filename)
{
     //bsp_sdcard_unmount();
    //  bsp_sdcard_mount();

    /*保存到sd卡的image文件夹下*/
    
    lv_coord_t width = lv_obj_get_width(obj);
    lv_coord_t height = lv_obj_get_height(obj);
    ESP_LOGI(TAG, "Creating screenshot of %dx%d", width, height);
    if (width == 0 || height == 0) {
        LV_LOG_WARN("Object has zero size, cannot take snapshot");
        return NULL;
    }
    // 调用LVGL的快照功能获取图像描述符
    lv_img_dsc_t *snapshot = md_lv_snapshot_take(obj, cf);

    if (snapshot) // 如果成功获取快照
    {
        if (try_sdcard_mount() != ESP_OK) {
            ESP_LOGE(TAG, "Failed to mount SD card");
            //return false; // 获取快照失败，返回失败
        } else {
            // 确保目录存在
            struct stat st = { 0 };
            if (stat(SCREENSHOT_SD_PATH, &st) == -1) {
                mkdir(SCREENSHOT_SD_PATH, 0755);
            }
            char dir_path[SCREENSHOT_SD_PATH_MAX];
            sprintf(dir_path, "%s/%s", SCREENSHOT_SD_PATH, filename);
            // 对快照数据进行预处理（根据颜色深度和保存格式调整数据）
            //rgb565转rgb888
           md_data_pre_processing(snapshot, LV_COLOR_DEPTH, screenshot_sv);

            if (screenshot_sv == SCREENSHOT_SV_JPEG) // 保存为JPEG
            {
                if (LV_COLOR_DEPTH == 16) // 16位颜色深度
                {
                    //ESP_LOGI(TAG, "screenshot filename %s", dir_path);
                    // 24位（RGB888）保存为JPEG
                    tje_encode_to_file(dir_path, snapshot->header.w, snapshot->header.h, 3, snapshot->data);
                }
            }
        }

        // 释放快照内存
        md_lv_snapshot_free(snapshot);
        try_sdcard_unmount(); // 卸载SD卡

        return true; // 返回成功
    }
    return false; // 获取快照失败，返回失败
}

/*=====================
 * Other functions
 *====================*/

/**********************
 *   STATIC FUNCTIONS
 **********************/

// /**
//  * @brief 数据预处理函数，根据颜色深度和保存格式调整图像数据
//  * @param snapshot 图像描述符指针
//  * @param bpp 颜色深度（bits per pixel）
//  * @param screenshot_sv 截图保存格式
//  */
// static void data_pre_processing(lv_img_dsc_t *snapshot, uint16_t bpp, screenshot_sv_t screenshot_sv)
// {
//     if (bpp == 16) // 处理16位颜色深度（RGB565）
//     {
//         uint16_t rgb565_data = 0;
//         uint32_t count = 0;
//         // 遍历每个像素
//         for (int w = 0; w < snapshot->header.w; w++) {
//             for (int h = 0; h < snapshot->header.h; h++) {
//                 // 从数据中读取16位RGB565值（小端序）
//                 rgb565_data = (uint16_t)((*(uint8_t *)(snapshot->data + count + 1) << 8) | *(uint8_t *)(snapshot->data + count));

//                 // 根据保存格式进行数据转换
//                 if ((screenshot_sv == SCREENSHOT_SV_PNG) || (screenshot_sv == SCREENSHOT_SV_JPEG)) {
//                     // 转换为RGB888格式（用于PNG和JPEG）
//                     // 提取R分量（5位->8位），左移3位相当于乘以8（近似缩放）
//                     *(uint8_t *)(snapshot->data + count) = (uint8_t)(((rgb565_data >> 11) & 0x1F) << 3);
//                     // 提取G分量（6位->8位），左移2位相当于乘以4（近似缩放）
//                     *(uint8_t *)(snapshot->data + count + 1) = (uint8_t)(((rgb565_data >> 5) & 0x3F) << 2);
//                     // 提取B分量（5位->8位），左移3位相当于乘以8（近似缩放）
//                     *(uint8_t *)(snapshot->data + count + 2) = (uint8_t)(((rgb565_data >> 0) & 0x1F) << 3);
//                 } 
//                 count += 3; // 移动到下一个像素（每个像素现在占3字节）
//             }
//         }
//     }
// }
static void md_data_pre_processing(lv_img_dsc_t *snapshot, uint16_t bpp, screenshot_sv_t screenshot_sv)
{
    // 首先检查是否需要转换（PNG/JPEG且16bpp，或BMP且16bpp，或PNG/JPEG且32bpp）
    if (bpp == 16) {
        uint32_t pixel_count = snapshot->header.w * snapshot->header.h;
        uint8_t *new_data = NULL;
        uint32_t new_data_size = 0;
        uint32_t src_index = 0;
        uint32_t dst_index = 0;

        // 计算新缓冲区大小
        if (bpp == 16) {
            // RGB565 -> RGB888/BGR888, 2字节/像素 -> 3字节/像素
            new_data_size = pixel_count * 3;
        }
        // 分配新缓冲区
        new_data = (uint8_t *)heap_caps_malloc(new_data_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
        if (new_data == NULL) {
            LV_LOG_ERROR("Failed to allocate memory for image data conversion!");
            return; // 分配失败，直接返回
        }
        for (uint32_t i = 0; i < pixel_count; i++) {
            // 从原始数据(src)读取RGB565值 (小端序)
            // 假设snapshot->data是uint16_t数组的uint8_t视图
            uint16_t rgb565 = *((uint16_t *)(&snapshot->data[src_index]));
            src_index += 2;

            // 分解RGB565
            uint8_t r = (rgb565 >> 11) & 0x1F;
            uint8_t g = (rgb565 >> 5) & 0x3F;
            uint8_t b = rgb565 & 0x1F;

            // 缩放至8位 
            r = (r << 3) | (r >> 2); // 更精确的缩放： r * 255 / 31
            g = (g << 2) | (g >> 4); // 更精确的缩放： g * 255 / 63
            b = (b << 3) | (b >> 2); // 更精确的缩放： b * 255 / 31

            if ((screenshot_sv == SCREENSHOT_SV_JPEG)) {
                // RGB888 格式
                new_data[dst_index++] = r;
                new_data[dst_index++] = g;
                new_data[dst_index++] = b;
            } 

          //  snapshot->header.cf = LV_IMG_CF_TRUE_COLOR_888;
        }
        heap_caps_free((void *)snapshot->data);
        snapshot->data = new_data;
    }
}


/*******************************************实现一键截图，自动生成文件名******************************************************************************/


static void screenshot_auto_create(lv_obj_t *obj)
{
    time_t now;
    struct tm timeinfo;
    char filename[32] = { 0 };

    // 获取当前时间
    time(&now);
    localtime_r(&now, &timeinfo);

    // 生成文件名（格式：YYYYMMDD_HHMMSS.jpg）
    strftime(filename, sizeof(filename), "%Y%m%d_%H%M%S.jpg", &timeinfo);

    // 保存截图（使用JPEG格式）
    if (screenshot_create(obj, LV_IMG_CF_TRUE_COLOR, SCREENSHOT_SV_JPEG, filename)) {
        ESP_LOGI(TAG, "Screenshot saved successfully: %s", filename);
        // // 保存最新文件名（不含路径）
        // strlcpy(latest_filename, filename, sizeof(latest_filename));
    } else {
        ESP_LOGE(TAG, "Failed to save screenshot");
    }
}



// 定义按键GPIO引脚
#define SCREENSHOT_BUTTON_GPIO GPIO_NUM_0
// 特殊消息值，用于通知任务退出
#define TASK_EXIT_MSG 0xA5A5A5A5
// 中断队列
static QueueHandle_t gpio_evt_queue = NULL;
// 任务句柄
static TaskHandle_t button_task_handle = NULL;
// GPIO中断处理函数
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
    uint32_t gpio_num = (uint32_t)arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
// 按键处理任务
static void button_task(void *arg)
{
    uint32_t io_num;

    for (;;) {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            // 检查是否为退出消息
            if (io_num == TASK_EXIT_MSG) {
                ESP_LOGI(TAG, "Button task received exit message");
                break;
            }
            // 检查是否为截图按钮
            if (io_num == SCREENSHOT_BUTTON_GPIO) {
                // 获取当前按键状态（确认是按下还是释放）
                int level = gpio_get_level(io_num);

                // （下降沿）
                if (level == 0) {
                    ESP_LOGI(TAG, "get_current_func_type:%d", get_current_func_type());

                    // 在主循环或GUI任务中处理截图，而不是在中断任务中直接调用
                    // 这里可以设置一个标志或发送事件给主任务
                    lv_obj_t *current_obj=get_current_func_obj();
                    screenshot_auto_create(current_obj); // 假设截取当前屏幕
                }
            }
        }
    }
    vTaskDelete(NULL);
}
// 初始化截图按钮
void screenshot_button_init(void)
{
    // 创建队列
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));

    // 配置GPIO
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << SCREENSHOT_BUTTON_GPIO),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE, // 启用上拉电阻
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_NEGEDGE, // 下降沿触发（按键按下）
    };
    gpio_config(&io_conf);

    // 安装GPIO ISR服务
    gpio_install_isr_service(0);

    // 添加ISR处理程序
    gpio_isr_handler_add(SCREENSHOT_BUTTON_GPIO, gpio_isr_handler, (void *)SCREENSHOT_BUTTON_GPIO);
    
        // 创建按键处理任务
        //xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);
    xTaskCreateWithCaps(button_task, "button_task", 12 * 1024, NULL, 6, &button_task_handle, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
    ESP_LOGI(TAG, "Screenshot button initialized on GPIO %d", SCREENSHOT_BUTTON_GPIO);
}
// 反初始化截图按钮
void screenshot_button_deinit(void)
{
    if (gpio_evt_queue != NULL) {
        // 首先移除ISR处理程序，防止新的中断
        gpio_isr_handler_remove(SCREENSHOT_BUTTON_GPIO);

        // 禁用GPIO中断
        gpio_intr_disable(SCREENSHOT_BUTTON_GPIO);

        // 如果有任务运行，发送退出消息
        if (button_task_handle != NULL) {
            uint32_t exit_msg = TASK_EXIT_MSG;
            xQueueSend(gpio_evt_queue, &exit_msg, portMAX_DELAY);

            // 等待任务退出（最多等待1秒）
            if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
                ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(1000));
            }

            button_task_handle = NULL;
        }

        // 删除队列
        vQueueDelete(gpio_evt_queue);
        gpio_evt_queue = NULL;

        ESP_LOGI(TAG, "Screenshot button deinitialized");
    }
}